package com.startx.http.system.encrypt.rsa;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

/**
 * @Description: 序列化或反序列化对象
 * @date 2015年9月10日 上午12:02:12
 */

public class Serializer {
	
	private static final Logger Log4j = Logger.getLogger(Serializer.class);
	/**
	 * 序列化
	 * 
	 * @param obj
	 * @return
	 */
	public static byte[] serialize(Object obj) {
		ByteArrayOutputStream bos = null;
		ObjectOutputStream oos = null;
		try {
			bos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(bos);
			oos.writeObject(obj);
			return bos.toByteArray();
		} catch (IOException e) {
			Log4j.fatal(e.getMessage(), e);
		} finally {
			try {
				if (oos != null)
					oos.close();
				if (bos != null)
					bos.close();
			} catch (IOException e) {
				Log4j.fatal(e.getMessage(), e);
			}
		}
		return new byte[] {};
	}

	/**
	 * 反序列化
	 * 
	 * @param bs
	 * @return
	 */
	public static Object deserialize(byte[] bs) {
		ByteArrayInputStream bis = null;
		ObjectInputStream ois = null;
		try {
			bis = new ByteArrayInputStream(bs);
			ois = new ObjectInputStream(bis);
			return ois.readObject();
		} catch (ClassNotFoundException e) {
			Log4j.fatal(e.getMessage(), e);
		} catch (IOException e) {
			Log4j.fatal(e.getMessage(), e);
		} finally {
			try {
				if (ois != null)
					ois.close();
				if (bis != null)
					bis.close();
			} catch (IOException e) {
				Log4j.fatal(e.getMessage(), e);
			}
		}
		return null;
	}

	/**
	 * 序列化Entity Type
	 * 
	 * @param obj
	 * @return
	 */
	public static Map<byte[], byte[]> make(Object obj) {
		try {
			Class<?> clz = obj.getClass();
			if (isBaseType(clz) || clz.isAnnotation() || clz.isInterface()
					|| clz.isArray() || clz.isEnum()) {
				Log4j.fatal("error type");
			}
			Map<byte[], byte[]> ms = new HashMap<byte[], byte[]>();
			Field[] fds = clz.getDeclaredFields();
			for (Field f : fds) {
				f.setAccessible(true);
				Object value = f.get(obj);
				if (value == null)
					continue;
				if (isBaseType(value.getClass())) {
					ms.put(f.getName().getBytes(), String.valueOf(value)
							.getBytes("utf-8"));
				} else {
					ms.put(f.getName().getBytes(), serialize(value));
				}
			}
			return ms;
		} catch (SecurityException | IllegalArgumentException | IllegalAccessException
				| UnsupportedEncodingException e) {
			Log4j.fatal(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 解析Entity Type
	 * 
	 * @param obj
	 * @return
	 */
	public static Object demake(Map<byte[], byte[]> vs, Class<?> clz) {

		try {
			Field[] fs = clz.getDeclaredFields();
			Constructor<?> con = clz.getDeclaredConstructor();
			con.setAccessible(true);
			Object obj = con.newInstance();
			for (Field f : fs) {
				f.setAccessible(true);
				Class<?> type = f.getType();
				byte[] bs = vs.get(f.getName().getBytes());
				if (bs == null || bs.length <= 0)
					continue;
				if (type == String.class) {
					f.set(obj, new String(bs, "utf-8"));
				} else if (type == Integer.class || type == int.class) {
					f.set(obj, Integer.valueOf(new String(bs, "utf-8")));
				} else if (type == Short.class || type == short.class) {
					f.set(obj, Short.valueOf(new String(bs, "utf-8")));
				} else if (type == Long.class || type == long.class) {
					f.set(obj, Long.valueOf(new String(bs, "utf-8")));
				} else if (type == Float.class || type == float.class) {
					f.set(obj, Float.valueOf(new String(bs, "utf-8")));
				} else if (type == Double.class || type == double.class) {
					f.set(obj, Double.valueOf(new String(bs, "utf-8")));
				} else if (type == Boolean.class || type == boolean.class) {
					f.set(obj, Boolean.valueOf(new String(bs, "utf-8")));
				} else if (type == char.class) {
					f.set(obj, (new String(bs, "utf-8")).toCharArray()[0]);
				} else {
					f.set(obj, deserialize(bs));
				}
			}
			
			return obj;
		} catch (SecurityException | NoSuchMethodException | InstantiationException | IllegalAccessException
				| IllegalArgumentException | InvocationTargetException | UnsupportedEncodingException e) {
			Log4j.fatal(e.getMessage(), e);
		}

		return null;
	}

	/**
	 * 判断是否基本数据类型
	 * @param clz
	 * @return
	 */
	private static boolean isBaseType(Class<?> clz) {
		if (clz == String.class || clz == Integer.class || clz == Long.class
				|| clz == Short.class || clz == Float.class
				|| clz == Double.class || clz == char.class
				|| clz == Boolean.class || clz == int.class
				|| clz == long.class || clz == short.class
				|| clz == float.class || clz == double.class
				|| clz == boolean.class) {
			return true;
		} else {
			return false;
		}
	}
}